package core;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import weka.core.Attribute;
import weka.core.FastVector;
import weka.core.Instance;
import weka.core.Instances;
import edu.cmu.minorthird.classify.ClassLabel;
import edu.cmu.minorthird.classify.Example;
import edu.cmu.minorthird.classify.Feature;
import edu.cmu.minorthird.classify.sequential.SequenceDataset;


public class Ficheiros {
	
	public File[] trainSet;
	public File[] testSet;
	public Hierarquia hierarquia;
	public Corpus corpus;
	public Instances wekaTrainingInstances;
	public Instances wekaTestInstances;
	public SequenceDataset minorthirdTrainingInstances = null;
	public SequenceDataset minorthirdTestInstances = null;
	
	
	public Ficheiros(Simulacao _simulacao, Corpus _corpus, Hierarquia _hierarquia){
		trainSet = _simulacao.listaFicheirosTreino;
		testSet = _simulacao.listaFicheirosTeste;
		hierarquia = _hierarquia;
		corpus=_corpus;
	}
	
	public void init() throws IOException{
		wekaTrainingInstances = geraFicheiroWeka(trainSet, true);
		wekaTestInstances = geraFicheiroWeka(testSet, false);
		geraFicheiroMinorthird();
	}


	private void geraFicheiroMinorthird() throws IOException {
		
		Instances dsetWeka;
		if(minorthirdTrainingInstances==null)
			dsetWeka = wekaTrainingInstances;
		else
			dsetWeka = wekaTestInstances;
		
        dsetWeka.setClassIndex(dsetWeka.numAttributes() - 1);
        
        SequenceDataset dsetM3rd = new SequenceDataset();
        
        Enumeration e = dsetWeka.enumerateInstances();
        while (e.hasMoreElements()) {
            weka.core.Instance instWeka = (weka.core.Instance)e.nextElement();
            
            edu.cmu.minorthird.classify.MutableInstance instM3rd = new edu.cmu.minorthird.classify.MutableInstance();
            
            // Iterate over the Weka instance features and convert each to its corresponding MinorThird instance feature
            int numAttrs = instWeka.numAttributes(); 
            for (int i = 0; i < numAttrs; ++i) {
                if (i == instWeka.classIndex()) continue; // skip the class
                if (instWeka.isMissing(i)) continue; // skip missing features
                instM3rd.addNumeric(new Feature(instWeka.attribute(i).name()),instWeka.value(i));
            }
            // Add the converted instance to the MinorThird dataset
            dsetM3rd.add(new Example(instM3rd,new ClassLabel(dsetWeka.classAttribute().value((int)instWeka.classValue()))));
        }
        
        if(minorthirdTrainingInstances==null)
        	minorthirdTrainingInstances=dsetM3rd;
        else
        	minorthirdTestInstances=dsetM3rd;
	}
            
            
            
            
	public Instances geraFicheiroWeka(File[] docSet, Boolean criarFicheiro){
		
		//Inicializa lista atributos do feature vector -> Vector de features
		int numFeatures = corpus.listaDocumentos[0].sentenceList[0].featureVector.split(" ").length;
		Attribute[] atributos = new Attribute[numFeatures];
		for(int i=0; i<numFeatures; i++){
			atributos[i] = new Attribute("f"+i);
		}
		
		//Inicializa lista classes finais -> Class do feature vector
		ArrayList<String> listaLabels = devolveLabelsHierarquia(hierarquia);
		FastVector classesLabels = new FastVector(listaLabels.size());
		for (String it : listaLabels) {
			classesLabels.addElement(it);
		}
		Attribute classes = new Attribute("classes", classesLabels);
		
		//Cria vector feature com o par (feature vector, class)
		FastVector attributes = new FastVector(numFeatures+1); 
		for(int i=0; i<numFeatures; i++){
			attributes.addElement(atributos[i]);
		}
		attributes.addElement(classes);
		
		//Transforma feature vector criado com par (feature vector, class) numa lista de instances
		Instances instances = new Instances("weka",attributes,0);
		
		//Carregamento dos feature vectors para a lista de instances
		for(int a=0; a<corpus.listaDocumentos.length; a++){
		
			//So o coloca nas instances se for um documento para processar
			if(!documentoParaProcessar(docSet, corpus.listaDocumentos[a].document)){
				continue;
			}
			
			for(int b=0; b<corpus.listaDocumentos[a].sentenceList.length; b++){
				Instance inst = new Instance(numFeatures+1);
				String[] featureVector = corpus.listaDocumentos[a].sentenceList[b].featureVector.split(" ");
				
				for(int c=0; c<featureVector.length; c++){
					if(featureVector[c].equals(""))
						continue;
					inst.setValue(atributos[c], Double.parseDouble(featureVector[c]));
				}
				inst.setValue(classes, corpus.listaDocumentos[a].sentenceList[b].categoriaTemp);
				instances.add(inst);
				if(criarFicheiro==false){
					corpus.listaDocumentos[a].sentenceList[b].instanceWeka=inst;
				}
			}
		}
		
		//System.out.println(instances);
		return instances;
		
	}

	public ArrayList<String> devolveLabelsHierarquia(Hierarquia hierarquia){
		
		int nivelActual = hierarquia.nivelHierarquicoActual;
		ArrayList<String> listaLabels = new ArrayList<String>();
		
		for(int i=nivelActual; i>=0; i--){
			Set<Map.Entry<String,String>> nivelHierarquico = hierarquia.niveisHierarquia[i].entrySet();
			Iterator<Map.Entry<String,String>> it = nivelHierarquico.iterator();
			while(it.hasNext()){
				Map.Entry<String,String> me = (Map.Entry<String,String>)it.next();
				listaLabels.add(me.getKey());
			}
		}
		return listaLabels;
	}
	
	public Boolean documentoParaProcessar(File[] documentosAprocesar, File docActual){
		
		for (File it : documentosAprocesar) {
			if(it.getName().equals(docActual.getName())){
				return true;
			}
		}
		return false;
	}
	
	
	
}
